package com.ztjava.ext.auth.tool;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.jfinal.aop.Invocation;
import com.jfinal.kit.Ret;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.redis.Cache;
import com.jfinal.plugin.redis.Redis;
import com.ztjava.core.Constant;
import com.ztjava.core.tool.ViewTool;
import com.ztjava.core.utiliy.RequestUtil;
import com.ztjava.ext.auth.annotation.AppMethod;
import com.ztjava.ext.auth.annotation.UserController;
import com.ztjava.ext.auth.annotation.UserMethod;
import com.ztjava.ext.auth.bean.AppSession;
import com.ztjava.ext.auth.bean.AuthSession;

public class AuthTool {

	public static final String token_name = "TOKEN";
	public static final String cookie = "cookie";
	public static final String para = "para";
	/***
	 * 移除SESSION
	 * @param authSession
	 */
	public static void removeUserSession(AuthSession authSession) {
		Cache cache = Redis.use();
		cache.del(authSession.getToken());
	}

	/***
	 * 创建SESSION并返还cookie
	 * 
	 * @param userSession
	 * @param seconds
	 * @param response
	 */
	public static void createUserSession(AuthSession userSession, int seconds,
			HttpServletResponse response,Integer yun_id) {
		String sessionId = makeSessionId(userSession.getPortal());
		userSession.setToken(sessionId);
		Cache cache = Redis.use();
		cache.set(sessionId, userSession);
		cache.expire(sessionId, seconds);

		Cookie cookie = new Cookie(makeCookieName(userSession.getPortal(),yun_id), sessionId);
		cookie.setPath("/");
		response.addCookie(cookie);
	}

	/***
	 * 创建SESSION并返还id
	 * 
	 * @param userSession
	 * @param seconds
	 * @return
	 */
	public static String createUserSession(AuthSession userSession, int seconds,Integer yun_id) {
		String sessionId = makeSessionId(userSession.getPortal());
		userSession.setToken(sessionId);
		Cache cache = Redis.use();
		if(yun_id!=null&&yun_id>0){
			cache.setex(yun_id+":"+sessionId, seconds, userSession);
		}else {
			cache.setex(sessionId, seconds, userSession);
		}
		return sessionId;
	}

	private static String makeSessionId(String portal){
		return Constant.R_PRE +  AuthTool.token_name+ ":"+ portal+":" + StrKit.getRandomUUID();
	}
	public static String makeCookieName(String portal,Integer yun_id){
		String name = "";
		if(yun_id==null||yun_id==0){
			name = Constant.R_PRE + portal	+ "_" + AuthTool.token_name;
		}else {
			name = Constant.R_PRE + portal	+ "_"+yun_id+"_" + AuthTool.token_name;
		}
		return name.replace(":", "_");
	}

	/***
	 * 更新SESSION
	 * 
	 * @param portal
	 * @param request
	 * @param authSession
	 */
	public static void updateUserSession(HttpServletRequest request,String tokenType, AuthSession authSession,Integer yun_id) {
		String sessionId = "";
		switch (tokenType) {
			case cookie:
				sessionId = RequestUtil.getCookie(request,makeCookieName(authSession.getPortal(),yun_id));
				break;
			case para:
				sessionId = request.getParameter(token_name);
				break;
			default:
				break;
		}
		Cache cache = Redis.use();
		cache.set(sessionId, authSession);
	}

	public AuthSession getAuthSession(String sessionId) {
		Cache cache = Redis.use();
		return cache.get(sessionId);
	}
	

	/***
	 * 权限验证
	 * 
	 * @param inv
	 * @return
	 */
	public static Ret check(Invocation inv) {
		if(inv.getMethod().isAnnotationPresent(AppMethod.class)){
			String sid = inv.getController().getPara("sid","");
			Cache cache = Redis.use();
			AppSession appSession = cache.hget(Constant.R_PRE+"AUTH:APP", sid);
			if(appSession==null){
				return Ret.create(Constant.RESULT, Constant.ERROR).set(Constant.MESSAGE, "应用不可用");
			}

			String rights = inv.getMethod().getAnnotation(AppMethod.class).value();
			if (!rights.equals("")&& appSession.getRights().indexOf(","+rights+",")==-1) {
				return Ret.create(Constant.RESULT, Constant.ERROR).set(Constant.MESSAGE, "应用权限不足");
			}
			inv.getController().setAttr(Constant.APPSESSION, appSession);
		}
		AuthSession userSession = null;
		String portal = "";
		if(inv.getController().getClass().isAnnotationPresent(UserController.class)){
			String sessionId = null;
			portal = inv.getController().getClass().getAnnotation(UserController.class).portal();
			String tokenType = inv.getController().getClass().getAnnotation(UserController.class).token();
			Integer yun_id = null;
			if(inv.getController().getClass().getAnnotation(UserController.class).yun().equals(Constant.T)){
				Cache cache = Redis.use();
				String domain = RequestUtil.getDomainOnly(inv.getController().getRequest());
				yun_id = cache.hget(Constant.R_YUN, domain);
				if(yun_id==null){
					return Ret.create(Constant.RESULT, Constant.ERROR).set(Constant.MESSAGE, "云服务已失效");
				}
				inv.getController().setAttr(Constant.YUN_ID,yun_id);
			}
			switch (tokenType) {
				case cookie:
					sessionId = RequestUtil.getCookie(inv.getController().getRequest(),makeCookieName(portal,yun_id));
					break;
				case para:
					sessionId = inv.getController().getPara(token_name);
					break;
				default:
					break;
			}
			// 使用Redis共享缓存
			Cache cache = Redis.use();
			if (sessionId != null && !sessionId.equals("")) {
				if(yun_id!=null&&yun_id>0){
					userSession = cache.get(yun_id+":"+sessionId);
				}else {
					userSession = cache.get(sessionId);
				}
			}
			if(userSession!=null){
				inv.getController().setAttr(Constant.AUTHSESSION, userSession);
			}
		}
		if(inv.getMethod().isAnnotationPresent(UserMethod.class)){
			String option = inv.getMethod().getAnnotation(UserMethod.class).option();
				// 可选验证
			if (option.equals("")|| (!option.equals("") && ViewTool.param(option,Constant.F).equals(Constant.T))) {
				if (userSession == null) {
					return Ret.create(Constant.RESULT, Constant.TIMEOUT).set(Constant.MESSAGE, "请先登录").set("portal", portal);
				}

				String rights = inv.getMethod().getAnnotation(UserMethod.class).value();
				if (!rights.equals("")&& userSession.getRights().get(portal + ":" + rights) == null) {
					return Ret.create(Constant.RESULT, Constant.ERROR).set(Constant.MESSAGE, "权限不足");
				}
			}
			
		}
		return Ret.create(Constant.RESULT, Constant.SUCCESS);
	}

}
